/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pe.gob.demo.abireader;


import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;

/**
 *
 */
public class AbiReader {
    
    private Card card = null;
    private CardChannel channel = null;
    private ResponseAPDU answer = null;
    
    private byte[] apSELECT_AUTHENTIC = {(byte)0x00,(byte)0xA4,(byte)0x04,(byte)0x00,(byte)0x10,(byte)0xA0,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x77,(byte)0x01,(byte)0x00,(byte)0x70,(byte)0x0A,(byte)0x10,(byte)0x00,(byte)0xF1,(byte)0x00,(byte)0x00,(byte)0x01,(byte)0x00};
    private byte[] select = {(byte)0x00,(byte)0xA4,(byte)0x00,(byte)0x00,(byte)0x02,(byte)0xFD,(byte)0x01};
    
    private String cui;
    private String verifier;
    private String primerApe;
    private String segundoApe;
    private String prenombres;
    private String sexo;
    private String ubigeoDomicilio;
    private String grupoVotacion;
    
    public AbiReader() {
       try {
          read();
       } catch (Exception ex) {
          Logger.getLogger(AbiReader.class.getName()).log(Level.SEVERE, null, ex);
       }
    }

    private void read() throws Exception {     
        
        //
        TerminalFactory factory = TerminalFactory.getDefault();
        List<CardTerminal> terminals = factory.terminals().list();
        if (terminals.isEmpty()) { throw new CardException("No terminals found.");}
        CardTerminal terminal = terminals.get(0);
        card = terminal.connect("*");
        channel = card.getBasicChannel();
        
        //
        answer = channel.transmit(new CommandAPDU(apSELECT_AUTHENTIC));
        int sw0 = answer.getSW();
        if (sw0 != 0x9000) { 
            throw new Exception("No se logro seleccionar Authentic");
        }        
        
        int lengthDEC;
        
        //
        answer = channel.transmit(new CommandAPDU(select));
        int sw = answer.getSW();
        if (sw == 0x9000) {
            byte[] tlvEf = answer.getData();
        
            //
            byte[] length3401Hex = new byte[2];
            System.arraycopy(tlvEf, 4, length3401Hex, 0, 2);
            lengthDEC = Integer.parseInt(fromBytesToString(length3401Hex), 16);
        } else{
            throw new Exception("No se logro seleccionar FD");
        }
        
        byte[] abiArray = new byte[lengthDEC];
        byte LE = (byte)0x00;
        for (int i=0; i<=(lengthDEC/ 256); i++) {
            if (i == (lengthDEC/256)) {
                LE = (byte)(lengthDEC % 256);
            }
            answer = channel.transmit(new CommandAPDU(new byte[]{(byte)0x00,(byte)0xB0,(byte)(i),(byte)0x00, LE}));
            if (answer.getSW() == 0x9000) {
                if (LE == 0x00) {
                    System.arraycopy(answer.getData(), 0, abiArray, (256*i), 256);
                } else {
                    System.arraycopy(answer.getData(), 0, abiArray, (256*i), (lengthDEC % 256));
                } 
            } else {
                throw new Exception("No se logro completar la lectura de bytes");
            }            
        }
        int ini, l;
        ini = 31;
        l = 8;
        cui = new String(abiArray, ini, l, "UTF-8");
        
        ini = ini + l + 2;
        l = abiArray[ini];
        verifier = new String(abiArray, ++ini, l, "UTF-8");
        
        ini = ini + l + 2;
        l = abiArray[ini];
        primerApe = new String(abiArray, ++ini, l, "UTF-8");
        
        ini = ini + l + 2;
        l = abiArray[ini];
        segundoApe = new String(abiArray, ++ini, l, "UTF-8");
        
        ini = ini + l + 2;
        l = abiArray[ini];
        prenombres = new String(abiArray, ++ini, l, "UTF-8");
        
        ini = ini + l + 2;
        l = abiArray[ini];
        sexo = new String(abiArray, ++ini, l, "UTF-8");
        
        ini = ini + l + 2;
        l = abiArray[ini];
        ubigeoDomicilio = new String(abiArray, ++ini, l, "UTF-8");
        
        ini = ini + l + 2;
        l = abiArray[ini];
        grupoVotacion = new String(abiArray, ++ini, l, "UTF-8");
    }
    
    public String getCui() {
       return cui;
    }
    
    public String getVerifCui() {
       return verifier;
    }
    
    public String getPrimerApellido() {
       return primerApe;
    }
    
    public String getSegundoApellido() {
       return segundoApe;
    }
    
    public String getPrenombres() {
       return prenombres;
    }
    
    public String getSexo() {
       return sexo;
    }
    
    public String getUbigeoDomicilio() {
       return ubigeoDomicilio;
    }
    
    public String getGrupoVotacion() {
       return grupoVotacion;
    }
    
    private String fromBytesToString(byte[] apdu){
        String cadena = "";
        for (int i=0; i<apdu.length; i++) {
            int b = apdu[i] & 0xFF;
            String auxa = Integer.toHexString(b).toUpperCase();
            if(auxa.length()==1) {
                cadena = cadena +"0"+auxa;
            }
            else {
                cadena = cadena + auxa;
            }
        }
        return cadena;
    } 
}
